﻿using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Drawing.Imaging;
using System.Drawing.Drawing2D;
using System.IO;
using System.Text;
using System.ComponentModel;
using System.Windows.Media.Imaging;
using System.Threading;
using System.Security.Cryptography;
using System.Windows.Threading;
using System.Windows;
using BrainTechLLC;
using BrainTechLLC.ThreadSafeObjects;

namespace WpfImageDuplicates
{
    public class ActionAndCallback<T> where T : class
    {
        public Action<T> _callback;
        public T _item;
        public object _lock;
        public Action<T> _performAction;

        public ActionAndCallback(T item, Action<T> performAction, Action<T> callback)
        {
            _callback = callback;
            _item = item;
            _performAction = performAction;
        }
    }

    public class LazyLoader<T> where T : class
    {
        public ThreadSafeQueue<ActionAndCallback<T>> _loadQueue;
        public object _lockObj = new object();
        public Action<T> _loadItemAction;
        public bool _initialized;

        public LazyLoader(Action<T> loadItemAction)
        {
            _loadItemAction = loadItemAction;
        }

        public void LazyLoad(T item, Action<T> callback)
        {
            LazyLoad(item, callback, null);
        }

        public void LazyLoad(T item, Action<T> callback, object lockObj)
        {
            CheckInit();
            var actionAndCallback = new ActionAndCallback<T>(item, _loadItemAction, callback);

            if (lockObj != null)
            {
                actionAndCallback._lock = lockObj;
            }

            _loadQueue.Enqueue(actionAndCallback);
        }

        public void CheckInit()
        {
            _lockObj.CheckInitialization(ref _initialized, () =>
            {
                _loadQueue = new ThreadSafeQueue<ActionAndCallback<T>>();
                ThreadStart ts = new ThreadStart(LazyLoadRunner);
                Thread t = ts.CreateAndRunThread();
                t.IsBackground = true;
            });
        }


        public void LazyLoadRunner()
        {
            while (true)
            {
                ActionAndCallback<T> item;
                bool any = false;

                while (_loadQueue.Dequeue(out item))
                {
                    any = true;

                    if (item._lock != null)
                    {
                        lock (item._lock)
                        {
                            item._performAction(item._item);
                        }
                    }
                    else
                    {
                        item._performAction(item._item);
                    }

                    if (item._callback != null)
                    {
                        item._callback(item._item);
                    }
                }

                if (!any)
                    Thread.Sleep(100);
                else
                    Thread.Sleep(10);
            }
        }
    }
}
